package org.bhf.security.authentication;

import org.bhf.facilities.Project;
import org.bhf.security.common.LoginID;

import javax.security.auth.Subject;
import javax.security.auth.login.CredentialExpiredException;
import javax.security.auth.login.FailedLoginException;

/**
 * Specifies the functional contract to the Authentication Facility.
 */
public interface AuthenticationFacility
{
    public enum PasswordEncoding
    {
        /** The password is in plaintext format */
        PLAINTEXT,

        /** The password is MD5 hashed and base 64 encoded */
        BASE64MD5,

        /** The password is MD5 hashed and base 64 encoded twice */
        BASE64MD5x2,

        /** Do not check the password - use with care */
        NONE
    }

    /**
     * Returns an array of password formats supported by this implementation.
     * Will not return <code>null</code> and will contain at least one element.
     * All implementations are required to support <code>PLAINTEXT</code>.
     *
     * @return An array of password formats supported by this implementation.
     */
    PasswordEncoding[]      getSupportedPasswordFormats();

    /**
     * <p>
     * Authenticates the specified Login ID and password under
     * the specified <code>Project</code>.  Authentication is successful
     * if the password matches the password for the specified Login ID
     * and if the corresponding User (for the Login ID) has a Role
     * in the specified Project.
     * </p>
     * <p>
     * Successful authentication returns a <code>Subject</code>
     * populated with the following:
     * </p>
     *
     * <ul>
     *      <li>
     *          Exactly one <code>org.bhf.security.common.UserID</code>
     *          as a <code>Principal</code>.
     *      </li>
     *      <li>
     *          Exactly one <code>org.bhf.security.common.LoginID</code>
     *          as a public credential.
     *      </li>
     *      <li>
     *          Exactly one <code>org.bhf.security.common.FullName</code>
     *          as a public credential.
     *      </li>
     *      <li>
     *          Exactly one <code>org.bhf.security.common.Location</code>
     *          as a public credential.
     *      </li>
     *      <li>
     *          One or more <code>org.bhf.security.common.Role</code>s
     *          as <code>Principal</code>s.  Only <code>Role</code>s
     *          in the specified <code>Project</code> will be populated.
     *      </li>
     * </ul>
     *
     * @param loginID the login ID.  Must not be <code>null</code>.
     * @param password the plain text password.  Must not be <code>null</code>.
     *      The caller is responsible for clearing out this array.
     * @param passwordFormat A supported password format. All implementations
     *      must support <code>PLAINTEXT</code>.
     * @param project the <code>Project</code> under which to authenticate.
     *      Must not be <code>null</code>.
     * @param log <code>true</code> to log this authentication attempt.
     *
     * @return a populated <code>Subject</code>.
     *      <code>AuthenticationFacility</code> implementations must ensure
     *      that this method does not return <code>null</code>.
     *
     * @throws FailedLoginException if authentication fails.
     *      Note that this is a subclass of <code>LoginException</code>.
     * @throws CredentialExpiredException if the password has expired.
     *      Note that this is a subclass of <code>LoginException</code>.
     * @throws LoginDisabledException if the Login account has been disabled.
     *      Note that this is a subclass of <code>LoginException</code>.
     * @throws LoginNotFoundException if the Login ID cannot be found.
     *      Note that this is a subclass of <code>LoginException</code>.
     * @throws LoginHoldException This login has been placed on temporary hold (strike out).
     *      Note that this is a subclass of <code>LoginException</code>.
     * @throws AuthenticationFacilityException if an internal error occurs.
     *      Note that this is a subclass of <code>LoginException</code>.
     * @throws IllegalArgumentException if <code>loginID == null</code>
     *      or if <code>password == null</code>.
     */
    Subject                 authenticate(
                                LoginID             loginID,
                                char[]              password,
                                PasswordEncoding    passwordFormat,
                                Project             project,
                                boolean             log
                            )
        throws FailedLoginException, CredentialExpiredException,
            LoginDisabledException, LoginNotFoundException,
            LoginHoldException, AuthenticationFacilityException;

    /**
     * Inform the facility that the user has logged out.
     *
     * @param loginID the login ID.  Must not be <code>null</code>.
     *
     * @throws LoginNotFoundException if the Login ID cannot be found.
     *      Note that this is a subclass of <code>LoginException</code>.
     * @throws AuthenticationFacilityException if an internal error occurs.
     *      Note that this is a subclass of <code>LoginException</code>.
     */
    void                    logout( LoginID loginID )
        throws LoginNotFoundException, AuthenticationFacilityException;

    /**
     * Returns the password to be used for signatures.
     *
     * @param loginID the login ID.  Must not be <code>null</code>.
     *
     * @return the signing password.
     *      <code>AuthenticationFacility</code> implementations must ensure
     *      that this method does not return <code>null</code>.
     *
     * @throws LoginNotFoundException if the Login ID cannot be found.
     *      Note that this is a subclass of <code>LoginException</code>.
     * @throws AuthenticationFacilityException if an internal error occurs.
     *      Note that this is a subclass of <code>LoginException</code>.
     * @throws IllegalArgumentException if <code>loginID == null</code>
     *      or if <code>password == null</code>.
     */
    String                  getSigningPassword( LoginID loginID )
        throws LoginNotFoundException, AuthenticationFacilityException;
    /**
     * Returns the <code>Project</code>s in which the User
     * has at least one <code>Role</code>.
     *
     * @param loginID the Login ID.  Must not be <code>null</code>.
     * @return the <code>Project</code>s in which the User
     *      has at least one <code>Role</code>.  Implementations
     *      must not return <code>null</code>, but may return
     *      an empty array.
     * @throws LoginNotFoundException if the Login ID cannot be found.
     *      Note that this is a subclass of <code>LoginException</code>.
     * @throws AuthenticationFacilityException if an internal error occurs.
     *      Note that this is a subclass of <code>LoginException</code>.
     * @throws IllegalArgumentException if <code>loginID == null</code>.
     */
    Project[]               getProjects( LoginID loginID )
        throws LoginNotFoundException, AuthenticationFacilityException;

    /**
     * Changes the password for the specified Login ID.
     *
     * @param loginID the Login ID.  Must not be <code>null</code>.
     * @param plainTextPassword the new password.  Must not be <code>null</code>.
     *
     * @throws InvalidPasswordException if the specified password is invalid
     *      (e.g. insufficient length).  Note that this is a subclass
     *      of <code>LoginException</code>.
     * @throws LoginNotFoundException if the Login ID cannot be found.
     *      Note that this is a subclass of <code>LoginException</code>.
     * @throws AuthenticationFacilityException if an internal error occurs.
     *      Note that this is a subclass of <code>LoginException</code>.
     * @throws IllegalArgumentException if <code>loginID == null</code>,
     *      <code>oldPassword == null</code>,
     *      or if <code>newPassword == null</code>.
     */
    void                    changePassword( LoginID loginID, char[] plainTextPassword )
    throws InvalidPasswordException, LoginNotFoundException, AuthenticationFacilityException;

    /**
     * Disables the specified Login ID.
     *
     * @param loginID the Login ID.  Must not be <code>null</code>.
     *
     * @throws LoginNotFoundException if the Login ID cannot be found.
     *      Note that this is a subclass of <code>LoginException</code>.
     * @throws AuthenticationFacilityException if an internal error occurs.
     *      Note that this is a subclass of <code>LoginException</code>.
     * @throws IllegalArgumentException if <code>loginID == null</code>.
     */
    void                    disable( LoginID loginID )
        throws LoginNotFoundException, AuthenticationFacilityException;

    /**
     * Enables the specified Login ID.
     *
     * @param loginID the Login ID.  Must not be <code>null</code>.
     *
     * @throws LoginNotFoundException if the Login ID cannot be found.
     *      Note that this is a subclass of <code>LoginException</code>.
     * @throws AuthenticationFacilityException if an internal error occurs.
     *      Note that this is a subclass of <code>LoginException</code>.
     * @throws IllegalArgumentException if <code>loginID == null</code>.
     */
    void                    enable( LoginID loginID )
        throws LoginNotFoundException, AuthenticationFacilityException;
}


